package com.sl.biz.core.websocket;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.google.common.collect.Maps;
import com.sl.auth.core.enums.SaClientTypeEnum;
import com.sl.auth.core.util.StpCompositeUtil;
import com.sl.biz.modular.process.controller.request.SquareLakeProcessRunRequest;
import com.sl.biz.modular.process.service.ProcessVersionContentBizService;
import com.sl.core.utils.JsonUtil;
import com.sl.core.engine.event.handler.ProcessLogHandler;
import com.sl.core.engine.log.ProcessLoggingEventListener;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.noear.socketd.transport.core.Entity;
import org.noear.socketd.transport.core.Listener;
import org.noear.socketd.transport.core.Session;
import org.noear.socketd.transport.core.impl.ConfigDefault;
import org.noear.socketd.transport.spring.websocket.ToSocketdWebSocketListener;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;

@Component
@Slf4j
public class ProcessWevSocketHandler extends ToSocketdWebSocketListener implements ProcessLogHandler, Listener {

    private final ProcessVersionContentBizService processService;

    //保存用户会话信息，用于服务端群发
    private static final Map<String, Session> WEB_SOCKET_SESSION_MAP = Maps.newConcurrentMap();

    public ProcessWevSocketHandler() {
        super(new ConfigDefault(false));
        this.processService = SpringUtil.getBean(ProcessVersionContentBizService.class);
        ProcessLoggingEventListener.INSTANCE = this;
    }


    @SneakyThrows
    public void sendMessage(Message message, String tid) {
        if (StrUtil.isBlank(tid)) {
            return;
        }
        Session webSocketSession = WEB_SOCKET_SESSION_MAP.get(tid);
        sendMessage(message, webSocketSession);
    }

    @SneakyThrows
    public void sendMessage(Message message, Session webSocketSession) {
        if (ObjectUtil.isNull(webSocketSession)) {
            return;
        }
        synchronized (webSocketSession) {
            if (webSocketSession.isValid()) {
                webSocketSession.send("message", Entity.of(JsonUtil.toStr(message)));
            }
        }

    }


    @Override
    public void log(String logStr, String tid) {
        this.sendMessage(new Message("log", logStr), tid);
    }


    @Override
    public boolean hasObservationFlag(String tid) {
        if (StrUtil.isBlank(tid)) {
            return false;
        }
        Session webSocketSession = WEB_SOCKET_SESSION_MAP.get(tid);
        return ObjectUtil.isNotNull(webSocketSession);
    }

    @Override
    public void onOpen(org.noear.socketd.transport.core.Session session) throws IOException {
        String tid = session.param("tid");
        if (StrUtil.isBlank(tid)) {
            return;
        }

        if (WEB_SOCKET_SESSION_MAP.containsKey(tid)) {
            WEB_SOCKET_SESSION_MAP.remove(tid);
            //加入set中
            WEB_SOCKET_SESSION_MAP.put(tid, session);
        } else {
            //加入set中
            WEB_SOCKET_SESSION_MAP.put(tid, session);

        }
        new Thread(() -> {
            Map<String, Object> map = Maps.newHashMap();
            map.put("message", "连接成功");
            sendMessage(new Message("log", JsonUtil.toStr(map)), session);
        }).start();
    }

    @Override
    public void onMessage(org.noear.socketd.transport.core.Session session, org.noear.socketd.transport.core.Message message) throws IOException {
        String tid = session.param("tid");
        String token = session.param("token");
        String userId = StpCompositeUtil.getUserId(token, SaClientTypeEnum.B);
        String s = message.entity().dataAsString();
        //可以群发消息
        //消息保存到数据库、redis
        if (!JsonUtil.isJsonStr(s)) {
            return;
        }
        Param bean = JsonUtil.toBean(s, Param.class);
        String type = bean.getType();
        if (StrUtil.equals(type, "run")) {
            //接收到消息 需要驱动
            SquareLakeProcessRunRequest runRequest = new SquareLakeProcessRunRequest();
            runRequest.setId(bean.getId());
            runRequest.setParam(bean.getParam());
            runRequest.setTid(tid);
            runRequest.setUserId(userId);
            runRequest.setProcessVersion(bean.getProcessVersion());
            Object run = processService.run(runRequest);
            //获取到了返回值
            sendMessage(new Message("result", run), session);
        }
    }

    @Override
    public void onClose(org.noear.socketd.transport.core.Session session) {
        String tid =null;
        try{
            tid = session.param("tid");
        }catch (Exception e){
            log.error("关闭时获取tid失败");
        }
        if (WEB_SOCKET_SESSION_MAP.containsKey(tid)) {
            WEB_SOCKET_SESSION_MAP.remove(tid);
        }
    }

    @Override
    public void onError(org.noear.socketd.transport.core.Session session, Throwable error) {
        error.printStackTrace();
        sendMessage(new Message("error", ExceptionUtil.stacktraceToString(error)), session);

    }


    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Param {

        private String type;

        private String id;

        private String processVersion;

        private Object param;

    }

}
